package fr.jade.fraclite;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.Type;

public class GenericComponentInterface extends BasicComponentInterface implements InvocationHandler {
  
  //-------------------------------------------------------------------------
  // Constructors
  // -------------------------------------------------------------------------
  
  /**
   * Constructs a new {@link GenericComponentInterface}.
   *
   * @param owner the component to which the interface belongs. If this
   *      parameter is <tt>null</tt> the owner is set to the interface itself,
   *      which must therefore be a {@link Component} interface.
   * @param name the name of the interface.
   * @param type the type of the interface.
   * @param isInternal <tt>true</tt> if the interface is an internal interface.
   * @param impl the object that implements the interface.
   */

  public GenericComponentInterface (final Component owner, final String name, final Type type, final boolean isInternal, final Object impl) {
    super(owner,name,type,isInternal,impl);
  }

  //-------------------------------- InvocationHandler -----------------------------------------
  
  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
    Object target = this;
    if(isDelagatedMethod(m)){
      if(impl == null){
        throw new NullPointerException("Trying to invoke a method on a client interface, or on a server interface whose complementary interface is not bound.");
      }else{
        target = impl;
      }
      
    }
    try{
      return m.invoke(target, args);
    }catch(InvocationTargetException ite){
      throw ite.getCause();
    }
  }

  protected boolean isDelagatedMethod(Method target) throws Throwable{
    try {
      this.getClass().getMethod(target.getName(), target.getParameterTypes());
      return false;
    } catch (NoSuchMethodException e) {
      return true;
    }
  }
}